# BirthWatch 0.5.1
# Copyright (C) 2007-2009, Floriano Scioscia
#
# A tool for Python S60 to add calendar entries for contacts' birthdays
#
# This program is free software; you can redistribute it and/or modify it under the terms
# of the GNU General Public License as published by the Free Software Foundation;
# either version 2 of the License, or (at your option) any later version.
# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the GNU General Public License for more details.

import e32
import appuifw
import e32calendar
import contacts
import time

SIS_VERSION = u"0.5.1"

class BirthdayEntry:

	def __init__(self, name, surname, birthday):
		self.marker = u"- BW"
		self.name = name
		self.surname = surname
		self.birthday = birthday
		self.n = 10  # number of years to repeat

	def __cmp__(self, other):
		b1 = self.get_birthday_string()
		b2 = other.get_birthday_string()
		if b1 < b2:
			return -1
		else:
			return 1

	def get_birthday_string(self):
		return time.strftime("%m/%d", time.localtime(self.birthday))

	def get_birthday_year(self):
		return time.strftime("%Y", time.localtime(self.birthday))

	def get_label(self):
		return self.get_birthday_string() + u": " + self.get_full_name()

	def get_full_name(self):
		return self.name + u" " + self.surname

	def get_anniv_label(self):
		limit = 20      # total length must be <=32 and tag length is 12
		return self.get_full_name()[0:limit] + u" (" + self.get_birthday_year() + u") " + self.marker

	def search_anniversary(self, cal_db):
		bd = time.localtime(self.birthday)
		year = time.localtime(time.time()).tm_year
		start = time.struct_time((bd.tm_year, bd.tm_mon, bd.tm_mday, 0, 0, 0, 0, 1, 0))
		end = time.struct_time((year+self.n, bd.tm_mon, bd.tm_mday, 0, 0, 0, 0, 1, 0))
		return cal_db.find_instances(time.mktime(start), time.mktime(end), self.get_anniv_label())

	def get_repeat(self):
		bd = time.localtime(self.birthday)
		year = time.localtime(time.time()).tm_year
		start = time.struct_time((year, bd.tm_mon, bd.tm_mday, 0, 0, 0, 0, 1, 0))
		end = time.struct_time((year+self.n, bd.tm_mon, bd.tm_mday, 0, 0, 0, 0, 1, 0))
		repeat = {'type':'yearly_by_date', 'interval':1, 'start':time.mktime(start), 'end':time.mktime(end)}
		return repeat

	def add_anniversary(self, cal_db):
		anniv_list = self.search_anniversary(cal_db)
		if len(anniv_list) == 0:
			anniv = cal_db.add_anniversary()
			anniv.set_time(self.birthday)
			anniv.content = self.get_anniv_label()
			repeat = self.get_repeat()
			anniv.set_repeat(repeat)
			anniv.commit()
			return 'added'
		else:
			return 'untouched'

	def remove_anniversary(self, cal_db):
		anniv_list = self.search_anniversary(cal_db)
		if len(anniv_list) > 0:
			cal_db.__delitem__(anniv_list[0]['id'])
			return 'removed'
		else:
			return 'not found'

class BirthWatch:

	def run(self):
		appuifw.note(u"Scanning contacts...");
		self.scan_contacts()
		indexes = appuifw.multi_selection_list(self.labels, style='checkbox', search_field=1)
		while len(indexes) > 0:
			action = appuifw.popup_menu([u"Add selected", u"Remove selected"], u"Select action:")
			if action == 0:
				self.add(indexes)
			elif action == 1:
				self.remove(indexes)
			indexes = appuifw.multi_selection_list(self.labels, style='checkbox', search_field=1)

	def scan_contacts(self):
		db = contacts.open()  # open database
		self.entries = []
		self.labels = []
		for entry_id in db:
			contact = db[entry_id]
			dates = contact.find(type='date')
			if len(dates) > 0:
				name = contact.find('first_name')[0].value
				surname = contact.find('last_name')[0].value
				ent = BirthdayEntry(name, surname, dates[0].value)
				self.entries.append(ent)
		self.entries.sort()
		for ent in self.entries:
			self.labels.append(ent.get_label())

	def add(self, indexes):
		cal_db = e32calendar.open()
		added = 0
		untouched = 0
		for i in indexes:
			e = self.entries[i]
			r = e.add_anniversary(cal_db)
			if r == 'added':
				added += 1
			elif r == 'untouched':
				untouched += 1
		appuifw.note(u"%d entries processed.\n%d added\n%d already found"%(len(indexes), added, untouched))

	def remove(self, indexes):
		cal_db = e32calendar.open()
		removed = 0
		notfound = 0
		for i in indexes:
			e = self.entries[i]
			r = e.remove_anniversary(cal_db)
			if r == 'removed':
				removed += 1
			elif r == 'not found':
				notfound += 1
		appuifw.note(u"%d entries processed.\n%d removed\n%d not found"%(len(indexes), removed, notfound))

	def about(self):
		appuifw.note(u'BirthWatch ' + SIS_VERSION + u'\nCopyright (C) 2007-2009, Floriano Scioscia\nfloriano.scioscia@libero.it\nEnjoy!')

# Startup
old_screen = appuifw.app.screen
old_body = appuifw.app.body
old_title = appuifw.app.title
old_menu = appuifw.app.menu
old_exit_handler = appuifw.app.exit_key_handler

b = BirthWatch()
b.run()

# Cleanup
appuifw.app.body = old_body
appuifw.app.title = old_title
appuifw.app.menu = old_menu
appuifw.app.exit_key_handler = old_exit_handler
appuifw.app.screen = old_screen
#appuifw.app.set_exit()
